home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / libogg / libogg-1.0rc3 / src / framing.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-27  |  48.3 KB  |  1,741 lines

  1. /********************************************************************
  2.  *                                                                  *
  3.  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
  4.  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
  5.  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  6.  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  7.  *                                                                  *
  8.  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
  9.  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
  10.  *                                                                  *
  11.  ********************************************************************
  12.  
  13.  function: code raw [Vorbis] packets into framed OggSquish stream and
  14.            decode Ogg streams back into raw packets
  15.  last mod: $Id: framing.c,v 1.20 2001/12/20 00:58:45 segher Exp $
  16.  
  17.  note: The CRC code is directly derived from public domain code by
  18.  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
  19.  for details.
  20.  
  21.  ********************************************************************/
  22.  
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <ogg/ogg.h>
  26.  
  27. /* A complete description of Ogg framing exists in docs/framing.html */
  28.  
  29. int ogg_page_version(ogg_page *og){
  30.   return((int)(og->header[4]));
  31. }
  32.  
  33. int ogg_page_continued(ogg_page *og){
  34.   return((int)(og->header[5]&0x01));
  35. }
  36.  
  37. int ogg_page_bos(ogg_page *og){
  38.   return((int)(og->header[5]&0x02));
  39. }
  40.  
  41. int ogg_page_eos(ogg_page *og){
  42.   return((int)(og->header[5]&0x04));
  43. }
  44.  
  45. ogg_int64_t ogg_page_granulepos(ogg_page *og){
  46.   unsigned char *page=og->header;
  47.   ogg_int64_t granulepos=page[13]&(0xff);
  48.   granulepos= (granulepos<<8)|(page[12]&0xff);
  49.   granulepos= (granulepos<<8)|(page[11]&0xff);
  50.   granulepos= (granulepos<<8)|(page[10]&0xff);
  51.   granulepos= (granulepos<<8)|(page[9]&0xff);
  52.   granulepos= (granulepos<<8)|(page[8]&0xff);
  53.   granulepos= (granulepos<<8)|(page[7]&0xff);
  54.   granulepos= (granulepos<<8)|(page[6]&0xff);
  55.   return(granulepos);
  56. }
  57.  
  58. int ogg_page_serialno(ogg_page *og){
  59.   return(og->header[14] |
  60.      (og->header[15]<<8) |
  61.      (og->header[16]<<16) |
  62.      (og->header[17]<<24));
  63. }
  64.  
  65. long ogg_page_pageno(ogg_page *og){
  66.   return(og->header[18] |
  67.      (og->header[19]<<8) |
  68.      (og->header[20]<<16) |
  69.      (og->header[21]<<24));
  70. }
  71.  
  72.  
  73.  
  74. /* returns the number of packets that are completed on this page (if
  75.    the leading packet is begun on a previous page, but ends on this
  76.    page, it's counted */
  77.  
  78. /* NOTE:
  79. If a page consists of a packet begun on a previous page, and a new
  80. packet begun (but not completed) on this page, the return will be:
  81.   ogg_page_packets(page)   ==1, 
  82.   ogg_page_continued(page) !=0
  83.  
  84. If a page happens to be a single packet that was begun on a
  85. previous page, and spans to the next page (in the case of a three or
  86. more page packet), the return will be: 
  87.   ogg_page_packets(page)   ==0, 
  88.   ogg_page_continued(page) !=0
  89. */
  90.  
  91. int ogg_page_packets(ogg_page *og){
  92.   int i,n=og->header[26],count=0;
  93.   for(i=0;i<n;i++)
  94.     if(og->header[27+i]<255)count++;
  95.   return(count);
  96. }
  97.  
  98.  
  99. #if 0
  100. /* helper to initialize lookup for direct-table CRC (illustrative; we
  101.    use the static init below) */
  102.  
  103. static ogg_uint32_t _ogg_crc_entry(unsigned long index){
  104.   int           i;
  105.   unsigned long r;
  106.  
  107.   r = index << 24;
  108.   for (i=0; i<8; i++)
  109.     if (r & 0x80000000UL)
  110.       r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
  111.                     polynomial, although we use an
  112.                     unreflected alg and an init/final
  113.                     of 0, not 0xffffffff */
  114.     else
  115.        r<<=1;
  116.  return (r & 0xffffffffUL);
  117. }
  118. #endif
  119.  
  120. static ogg_uint32_t crc_lookup[256]={
  121.   0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
  122.   0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
  123.   0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
  124.   0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
  125.   0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
  126.   0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
  127.   0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
  128.   0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
  129.   0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
  130.   0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
  131.   0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
  132.   0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
  133.   0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
  134.   0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
  135.   0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
  136.   0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
  137.   0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
  138.   0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
  139.   0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
  140.   0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
  141.   0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
  142.   0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
  143.   0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
  144.   0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
  145.   0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
  146.   0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
  147.   0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
  148.   0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
  149.   0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
  150.   0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
  151.   0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
  152.   0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
  153.   0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
  154.   0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
  155.   0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
  156.   0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
  157.   0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
  158.   0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
  159.   0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
  160.   0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
  161.   0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
  162.   0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
  163.   0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
  164.   0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
  165.   0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
  166.   0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
  167.   0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
  168.   0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
  169.   0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
  170.   0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
  171.   0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
  172.   0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
  173.   0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
  174.   0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
  175.   0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
  176.   0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
  177.   0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
  178.   0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
  179.   0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
  180.   0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
  181.   0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
  182.   0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
  183.   0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
  184.   0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
  185.  
  186. /* init the encode/decode logical stream state */
  187.  
  188. int ogg_stream_init(ogg_stream_state *os,int serialno){
  189.   if(os){
  190.     memset(os,0,sizeof(*os));
  191.     os->body_storage=16*1024;
  192.     os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
  193.  
  194.     os->lacing_storage=1024;
  195.     os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
  196.     os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
  197.  
  198.     os->serialno=serialno;
  199.  
  200.     return(0);
  201.   }
  202.   return(-1);
  203.  
  204. /* _clear does not free os, only the non-flat storage within */
  205. int ogg_stream_clear(ogg_stream_state *os){
  206.   if(os){
  207.     if(os->body_data)_ogg_free(os->body_data);
  208.     if(os->lacing_vals)_ogg_free(os->lacing_vals);
  209.     if(os->granule_vals)_ogg_free(os->granule_vals);
  210.  
  211.     memset(os,0,sizeof(*os));    
  212.   }
  213.   return(0);
  214.  
  215. int ogg_stream_destroy(ogg_stream_state *os){
  216.   if(os){
  217.     ogg_stream_clear(os);
  218.     _ogg_free(os);
  219.   }
  220.   return(0);
  221.  
  222. /* Helpers for ogg_stream_encode; this keeps the structure and
  223.    what's happening fairly clear */
  224.  
  225. static void _os_body_expand(ogg_stream_state *os,int needed){
  226.   if(os->body_storage<=os->body_fill+needed){
  227.     os->body_storage+=(needed+1024);
  228.     os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
  229.   }
  230. }
  231.  
  232. static void _os_lacing_expand(ogg_stream_state *os,int needed){
  233.   if(os->lacing_storage<=os->lacing_fill+needed){
  234.     os->lacing_storage+=(needed+32);
  235.     os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
  236.     os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
  237.   }
  238. }
  239.  
  240. /* checksum the page */
  241. /* Direct table CRC; note that this will be faster in the future if we
  242.    perform the checksum silmultaneously with other copies */
  243.  
  244. void ogg_page_checksum_set(ogg_page *og){
  245.   if(og){
  246.     ogg_uint32_t crc_reg=0;
  247.     int i;
  248.  
  249.     /* safety; needed for API behavior, but not framing code */
  250.     og->header[22]=0;
  251.     og->header[23]=0;
  252.     og->header[24]=0;
  253.     og->header[25]=0;
  254.     
  255.     for(i=0;i<og->header_len;i++)
  256.       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
  257.     for(i=0;i<og->body_len;i++)
  258.       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
  259.     
  260.     og->header[22]=crc_reg&0xff;
  261.     og->header[23]=(crc_reg>>8)&0xff;
  262.     og->header[24]=(crc_reg>>16)&0xff;
  263.     og->header[25]=(crc_reg>>24)&0xff;
  264.   }
  265. }
  266.  
  267. /* submit data to the internal buffer of the framing engine */
  268. int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
  269.   int lacing_vals=op->bytes/255+1,i;
  270.  
  271.   if(os->body_returned){
  272.     /* advance packet data according to the body_returned pointer. We
  273.        had to keep it around to return a pointer into the buffer last
  274.        call */
  275.     
  276.     os->body_fill-=os->body_returned;
  277.     if(os->body_fill)
  278.       memmove(os->body_data,os->body_data+os->body_returned,
  279.           os->body_fill);
  280.     os->body_returned=0;
  281.   }
  282.  
  283.   /* make sure we have the buffer storage */
  284.   _os_body_expand(os,op->bytes);
  285.   _os_lacing_expand(os,lacing_vals);
  286.  
  287.   /* Copy in the submitted packet.  Yes, the copy is a waste; this is
  288.      the liability of overly clean abstraction for the time being.  It
  289.      will actually be fairly easy to eliminate the extra copy in the
  290.      future */
  291.  
  292.   memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
  293.   os->body_fill+=op->bytes;
  294.  
  295.   /* Store lacing vals for this packet */
  296.   for(i=0;i<lacing_vals-1;i++){
  297.     os->lacing_vals[os->lacing_fill+i]=255;
  298.     os->granule_vals[os->lacing_fill+i]=os->granulepos;
  299.   }
  300.   os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
  301.   os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos;
  302.  
  303.   /* flag the first segment as the beginning of the packet */
  304.   os->lacing_vals[os->lacing_fill]|= 0x100;
  305.  
  306.   os->lacing_fill+=lacing_vals;
  307.  
  308.   /* for the sake of completeness */
  309.   os->packetno++;
  310.  
  311.   if(op->e_o_s)os->e_o_s=1;
  312.  
  313.   return(0);
  314. }
  315.  
  316. /* This will flush remaining packets into a page (returning nonzero),
  317.    even if there is not enough data to trigger a flush normally
  318.    (undersized page). If there are no packets or partial packets to
  319.    flush, ogg_stream_flush returns 0.  Note that ogg_stream_flush will
  320.    try to flush a normal sized page like ogg_stream_pageout; a call to
  321.    ogg_stream_flush does not gurantee that all packets have flushed.
  322.    Only a return value of 0 from ogg_stream_flush indicates all packet
  323.    data is flushed into pages.
  324.  
  325.    ogg_stream_page will flush the last page in a stream even if it's
  326.    undersized; you almost certainly want to use ogg_stream_pageout
  327.    (and *not* ogg_stream_flush) unless you need to flush an undersized
  328.    page in the middle of a stream for some reason. */
  329.  
  330. int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
  331.   int i;
  332.   int vals=0;
  333.   int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
  334.   int bytes=0;
  335.   long acc=0;
  336.   ogg_int64_t granule_pos=os->granule_vals[0];
  337.  
  338.   if(maxvals==0)return(0);
  339.   
  340.   /* construct a page */
  341.   /* decide how many segments to include */
  342.   
  343.   /* If this is the initial header case, the first page must only include
  344.      the initial header packet */
  345.   if(os->b_o_s==0){  /* 'initial header page' case */
  346.     granule_pos=0;
  347.     for(vals=0;vals<maxvals;vals++){
  348.       if((os->lacing_vals[vals]&0x0ff)<255){
  349.     vals++;
  350.     break;
  351.       }
  352.     }
  353.   }else{
  354.     for(vals=0;vals<maxvals;vals++){
  355.       if(acc>4096)break;
  356.       acc+=os->lacing_vals[vals]&0x0ff;
  357.       granule_pos=os->granule_vals[vals];
  358.     }
  359.   }
  360.   
  361.   /* construct the header in temp storage */
  362.   memcpy(os->header,"OggS",4);
  363.   
  364.   /* stream structure version */
  365.   os->header[4]=0x00;
  366.   
  367.   /* continued packet flag? */
  368.   os->header[5]=0x00;
  369.   if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
  370.   /* first page flag? */
  371.   if(os->b_o_s==0)os->header[5]|=0x02;
  372.   /* last page flag? */
  373.   if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
  374.   os->b_o_s=1;
  375.  
  376.   /* 64 bits of PCM position */
  377.   for(i=6;i<14;i++){
  378.     os->header[i]=(granule_pos&0xff);
  379.     granule_pos>>=8;
  380.   }
  381.  
  382.   /* 32 bits of stream serial number */
  383.   {
  384.     long serialno=os->serialno;
  385.     for(i=14;i<18;i++){
  386.       os->header[i]=(serialno&0xff);
  387.       serialno>>=8;
  388.     }
  389.   }
  390.  
  391.   /* 32 bits of page counter (we have both counter and page header
  392.      because this val can roll over) */
  393.   if(os->pageno==-1)os->pageno=0; /* because someone called
  394.                      stream_reset; this would be a
  395.                      strange thing to do in an
  396.                      encode stream, but it has
  397.                      plausible uses */
  398.   {
  399.     long pageno=os->pageno++;
  400.     for(i=18;i<22;i++){
  401.       os->header[i]=(pageno&0xff);
  402.       pageno>>=8;
  403.     }
  404.   }
  405.   
  406.   /* zero for computation; filled in later */
  407.   os->header[22]=0;
  408.   os->header[23]=0;
  409.   os->header[24]=0;
  410.   os->header[25]=0;
  411.   
  412.   /* segment table */
  413.   os->header[26]=vals&0xff;
  414.   for(i=0;i<vals;i++)
  415.     bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
  416.   
  417.   /* set pointers in the ogg_page struct */
  418.   og->header=os->header;
  419.   og->header_len=os->header_fill=vals+27;
  420.   og->body=os->body_data+os->body_returned;
  421.   og->body_len=bytes;
  422.   
  423.   /* advance the lacing data and set the body_returned pointer */
  424.   
  425.   os->lacing_fill-=vals;
  426.   memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
  427.   memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
  428.   os->body_returned+=bytes;
  429.   
  430.   /* calculate the checksum */
  431.   
  432.   ogg_page_checksum_set(og);
  433.  
  434.   /* done */
  435.   return(1);
  436. }
  437.  
  438.  
  439. /* This constructs pages from buffered packet segments.  The pointers
  440. returned are to static buffers; do not free. The returned buffers are
  441. good only until the next call (using the same ogg_stream_state) */
  442.  
  443. int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
  444.  
  445.   if((os->e_o_s&&os->lacing_fill) ||          /* 'were done, now flush' case */
  446.      os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
  447.      os->lacing_fill>=255 ||                  /* 'segment table full' case */
  448.      (os->lacing_fill&&!os->b_o_s)){          /* 'initial header page' case */
  449.         
  450.     return(ogg_stream_flush(os,og));
  451.   }
  452.   
  453.   /* not enough data to construct a page and not end of stream */
  454.   return(0);
  455. }
  456.  
  457. int ogg_stream_eos(ogg_stream_state *os){
  458.   return os->e_o_s;
  459. }
  460.  
  461. /* DECODING PRIMITIVES: packet streaming layer **********************/
  462.  
  463. /* This has two layers to place more of the multi-serialno and paging
  464.    control in the application's hands.  First, we expose a data buffer
  465.    using ogg_sync_buffer().  The app either copies into the
  466.    buffer, or passes it directly to read(), etc.  We then call
  467.    ogg_sync_wrote() to tell how many bytes we just added.
  468.  
  469.    Pages are returned (pointers into the buffer in ogg_sync_state)
  470.    by ogg_sync_pageout().  The page is then submitted to
  471.    ogg_stream_pagein() along with the appropriate
  472.    ogg_stream_state* (ie, matching serialno).  We then get raw
  473.    packets out calling ogg_stream_packetout() with a
  474.    ogg_stream_state.  See the 'frame-prog.txt' docs for details and
  475.    example code. */
  476.  
  477. /* initialize the struct to a known state */
  478. int ogg_sync_init(ogg_sync_state *oy){
  479.   if(oy){
  480.     memset(oy,0,sizeof(*oy));
  481.   }
  482.   return(0);
  483. }
  484.  
  485. /* clear non-flat storage within */
  486. int ogg_sync_clear(ogg_sync_state *oy){
  487.   if(oy){
  488.     if(oy->data)_ogg_free(oy->data);
  489.     ogg_sync_init(oy);
  490.   }
  491.   return(0);
  492. }
  493.  
  494. int ogg_sync_destroy(ogg_sync_state *oy){
  495.   if(oy){
  496.     ogg_sync_clear(oy);
  497.     _ogg_free(oy);
  498.   }
  499.   return(0);
  500. }
  501.  
  502. char *ogg_sync_buffer(ogg_sync_state *oy, long size){
  503.  
  504.   /* first, clear out any space that has been previously returned */
  505.   if(oy->returned){
  506.     oy->fill-=oy->returned;
  507.     if(oy->fill>0)
  508.       memmove(oy->data,oy->data+oy->returned,oy->fill);
  509.     oy->returned=0;
  510.   }
  511.  
  512.   if(size>oy->storage-oy->fill){
  513.     /* We need to extend the internal buffer */
  514.     long newsize=size+oy->fill+4096; /* an extra page to be nice */
  515.  
  516.     if(oy->data)
  517.       oy->data=_ogg_realloc(oy->data,newsize);
  518.     else
  519.       oy->data=_ogg_malloc(newsize);
  520.     oy->storage=newsize;
  521.   }
  522.  
  523.   /* expose a segment at least as large as requested at the fill mark */
  524.   return((char *)oy->data+oy->fill);
  525. }
  526.  
  527. int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
  528.   if(oy->fill+bytes>oy->storage)return(-1);
  529.   oy->fill+=bytes;
  530.   return(0);
  531. }
  532.  
  533. /* sync the stream.  This is meant to be useful for finding page
  534.    boundaries.
  535.  
  536.    return values for this:
  537.   -n) skipped n bytes
  538.    0) page not ready; more data (no bytes skipped)
  539.    n) page synced at current location; page length n bytes
  540.    
  541. */
  542.  
  543. long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
  544.   unsigned char *page=oy->data+oy->returned;
  545.   unsigned char *next;
  546.   long bytes=oy->fill-oy->returned;
  547.   
  548.   if(oy->headerbytes==0){
  549.     int headerbytes,i;
  550.     if(bytes<27)return(0); /* not enough for a header */
  551.     
  552.     /* verify capture pattern */
  553.     if(memcmp(page,"OggS",4))goto sync_fail;
  554.     
  555.     headerbytes=page[26]+27;
  556.     if(bytes<headerbytes)return(0); /* not enough for header + seg table */
  557.     
  558.     /* count up body length in the segment table */
  559.     
  560.     for(i=0;i<page[26];i++)
  561.       oy->bodybytes+=page[27+i];
  562.     oy->headerbytes=headerbytes;
  563.   }
  564.   
  565.   if(oy->bodybytes+oy->headerbytes>bytes)return(0);
  566.   
  567.   /* The whole test page is buffered.  Verify the checksum */
  568.   {
  569.     /* Grab the checksum bytes, set the header field to zero */
  570.     char chksum[4];
  571.     ogg_page log;
  572.     
  573.     memcpy(chksum,page+22,4);
  574.     memset(page+22,0,4);
  575.     
  576.     /* set up a temp page struct and recompute the checksum */
  577.     log.header=page;
  578.     log.header_len=oy->headerbytes;
  579.     log.body=page+oy->headerbytes;
  580.     log.body_len=oy->bodybytes;
  581.     ogg_page_checksum_set(&log);
  582.     
  583.     /* Compare */
  584.     if(memcmp(chksum,page+22,4)){
  585.       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
  586.      at all) */
  587.       /* replace the computed checksum with the one actually read in */
  588.       memcpy(page+22,chksum,4);
  589.       
  590.       /* Bad checksum. Lose sync */
  591.       goto sync_fail;
  592.     }
  593.   }
  594.   
  595.   /* yes, have a whole page all ready to go */
  596.   {
  597.     unsigned char *page=oy->data+oy->returned;
  598.     long bytes;
  599.  
  600.     if(og){
  601.       og->header=page;
  602.       og->header_len=oy->headerbytes;
  603.       og->body=page+oy->headerbytes;
  604.       og->body_len=oy->bodybytes;
  605.     }
  606.  
  607.     oy->unsynced=0;
  608.     oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
  609.     oy->headerbytes=0;
  610.     oy->bodybytes=0;
  611.     return(bytes);
  612.   }
  613.   
  614.  sync_fail:
  615.   
  616.   oy->headerbytes=0;
  617.   oy->bodybytes=0;
  618.   
  619.   /* search for possible capture */
  620.   next=memchr(page+1,'O',bytes-1);
  621.   if(!next)
  622.     next=oy->data+oy->fill;
  623.  
  624.   oy->returned=next-oy->data;
  625.   return(-(next-page));
  626. }
  627.  
  628. /* sync the stream and get a page.  Keep trying until we find a page.
  629.    Supress 'sync errors' after reporting the first.
  630.  
  631.    return values:
  632.    -1) recapture (hole in data)
  633.     0) need more data
  634.     1) page returned
  635.  
  636.    Returns pointers into buffered data; invalidated by next call to
  637.    _stream, _clear, _init, or _buffer */
  638.  
  639. int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
  640.  
  641.   /* all we need to do is verify a page at the head of the stream
  642.      buffer.  If it doesn't verify, we look for the next potential
  643.      frame */
  644.  
  645.   while(1){
  646.     long ret=ogg_sync_pageseek(oy,og);
  647.     if(ret>0){
  648.       /* have a page */
  649.       return(1);
  650.     }
  651.     if(ret==0){
  652.       /* need more data */
  653.       return(0);
  654.     }
  655.     
  656.     /* head did not start a synced page... skipped some bytes */
  657.     if(!oy->unsynced){
  658.       oy->unsynced=1;
  659.       return(-1);
  660.     }
  661.  
  662.     /* loop. keep looking */
  663.  
  664.   }
  665. }
  666.  
  667. /* add the incoming page to the stream state; we decompose the page
  668.    into packet segments here as well. */
  669.  
  670. int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
  671.   unsigned char *header=og->header;
  672.   unsigned char *body=og->body;
  673.   long           bodysize=og->body_len;
  674.   int            segptr=0;
  675.  
  676.   int version=ogg_page_version(og);
  677.   int continued=ogg_page_continued(og);
  678.   int bos=ogg_page_bos(og);
  679.   int eos=ogg_page_eos(og);
  680.   ogg_int64_t granulepos=ogg_page_granulepos(og);
  681.   int serialno=ogg_page_serialno(og);
  682.   long pageno=ogg_page_pageno(og);
  683.   int segments=header[26];
  684.   
  685.   /* clean up 'returned data' */
  686.   {
  687.     long lr=os->lacing_returned;
  688.     long br=os->body_returned;
  689.  
  690.     /* body data */
  691.     if(br){
  692.       os->body_fill-=br;
  693.       if(os->body_fill)
  694.     memmove(os->body_data,os->body_data+br,os->body_fill);
  695.       os->body_returned=0;
  696.     }
  697.  
  698.     if(lr){
  699.       /* segment table */
  700.       if(os->lacing_fill-lr){
  701.     memmove(os->lacing_vals,os->lacing_vals+lr,
  702.         (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
  703.     memmove(os->granule_vals,os->granule_vals+lr,
  704.         (os->lacing_fill-lr)*sizeof(*os->granule_vals));
  705.       }
  706.       os->lacing_fill-=lr;
  707.       os->lacing_packet-=lr;
  708.       os->lacing_returned=0;
  709.     }
  710.   }
  711.  
  712.   /* check the serial number */
  713.   if(serialno!=os->serialno)return(-1);
  714.   if(version>0)return(-1);
  715.  
  716.   _os_lacing_expand(os,segments+1);
  717.  
  718.   /* are we in sequence? */
  719.   if(pageno!=os->pageno){
  720.     int i;
  721.  
  722.     /* unroll previous partial packet (if any) */
  723.     for(i=os->lacing_packet;i<os->lacing_fill;i++)
  724.       os->body_fill-=os->lacing_vals[i]&0xff;
  725.     os->lacing_fill=os->lacing_packet;
  726.  
  727.     /* make a note of dropped data in segment table */
  728.     if(os->pageno!=-1){
  729.       os->lacing_vals[os->lacing_fill++]=0x400;
  730.       os->lacing_packet++;
  731.     }
  732.  
  733.     /* are we a 'continued packet' page?  If so, we'll need to skip
  734.        some segments */
  735.     if(continued){
  736.       bos=0;
  737.       for(;segptr<segments;segptr++){
  738.     int val=header[27+segptr];
  739.     body+=val;
  740.     bodysize-=val;
  741.     if(val<255){
  742.       segptr++;
  743.       break;
  744.     }
  745.       }
  746.     }
  747.   }
  748.   
  749.   if(bodysize){
  750.     _os_body_expand(os,bodysize);
  751.     memcpy(os->body_data+os->body_fill,body,bodysize);
  752.     os->body_fill+=bodysize;
  753.   }
  754.  
  755.   {
  756.     int saved=-1;
  757.     while(segptr<segments){
  758.       int val=header[27+segptr];
  759.       os->lacing_vals[os->lacing_fill]=val;
  760.       os->granule_vals[os->lacing_fill]=-1;
  761.       
  762.       if(bos){
  763.     os->lacing_vals[os->lacing_fill]|=0x100;
  764.     bos=0;
  765.       }
  766.       
  767.       if(val<255)saved=os->lacing_fill;
  768.       
  769.       os->lacing_fill++;
  770.       segptr++;
  771.       
  772.       if(val<255)os->lacing_packet=os->lacing_fill;
  773.     }
  774.   
  775.     /* set the granulepos on the last granuleval of the last full packet */
  776.     if(saved!=-1){
  777.       os->granule_vals[saved]=granulepos;
  778.     }
  779.  
  780.   }
  781.  
  782.   if(eos){
  783.     os->e_o_s=1;
  784.     if(os->lacing_fill>0)
  785.       os->lacing_vals[os->lacing_fill-1]|=0x200;
  786.   }
  787.  
  788.   os->pageno=pageno+1;
  789.  
  790.   return(0);
  791. }
  792.  
  793. /* clear things to an initial state.  Good to call, eg, before seeking */
  794. int ogg_sync_reset(ogg_sync_state *oy){
  795.   oy->fill=0;
  796.   oy->returned=0;
  797.   oy->unsynced=0;
  798.   oy->headerbytes=0;
  799.   oy->bodybytes=0;
  800.   return(0);
  801. }
  802.  
  803. int ogg_stream_reset(ogg_stream_state *os){
  804.   os->body_fill=0;
  805.   os->body_returned=0;
  806.  
  807.   os->lacing_fill=0;
  808.   os->lacing_packet=0;
  809.   os->lacing_returned=0;
  810.  
  811.   os->header_fill=0;
  812.  
  813.   os->e_o_s=0;
  814.   os->b_o_s=0;
  815.   os->pageno=-1;
  816.   os->packetno=0;
  817.   os->granulepos=0;
  818.  
  819.   return(0);
  820. }
  821.  
  822. static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
  823.  
  824.   /* The last part of decode. We have the stream broken into packet
  825.      segments.  Now we need to group them into packets (or return the
  826.      out of sync markers) */
  827.  
  828.   int ptr=os->lacing_returned;
  829.  
  830.   if(os->lacing_packet<=ptr)return(0);
  831.  
  832.   if(os->lacing_vals[ptr]&0x400){
  833.     /* we need to tell the codec there's a gap; it might need to
  834.        handle previous packet dependencies. */
  835.     os->lacing_returned++;
  836.     os->packetno++;
  837.     return(-1);
  838.   }
  839.  
  840.   if(!op && !adv)return(1); /* just using peek as an inexpensive way
  841.                                to ask if there's a whole packet
  842.                                waiting */
  843.  
  844.   /* Gather the whole packet. We'll have no holes or a partial packet */
  845.   {
  846.     int size=os->lacing_vals[ptr]&0xff;
  847.     int bytes=size;
  848.     int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
  849.     int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
  850.  
  851.     while(size==255){
  852.       int val=os->lacing_vals[++ptr];
  853.       size=val&0xff;
  854.       if(val&0x200)eos=0x200;
  855.       bytes+=size;
  856.     }
  857.  
  858.     if(op){
  859.       op->e_o_s=eos;
  860.       op->b_o_s=bos;
  861.       op->packet=os->body_data+os->body_returned;
  862.       op->packetno=os->packetno;
  863.       op->granulepos=os->granule_vals[ptr];
  864.       op->bytes=bytes;
  865.     }
  866.  
  867.     if(adv){
  868.       os->body_returned+=bytes;
  869.       os->lacing_returned=ptr+1;
  870.       os->packetno++;
  871.     }
  872.   }
  873.   return(1);
  874. }
  875.  
  876. int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
  877.   return _packetout(os,op,1);
  878. }
  879.  
  880. int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
  881.   return _packetout(os,op,0);
  882. }
  883.  
  884. void ogg_packet_clear(ogg_packet *op) {
  885.   _ogg_free(op->packet);
  886.   memset(op, 0, sizeof(*op));
  887. }
  888.  
  889. #ifdef _V_SELFTEST
  890. #include <stdio.h>
  891.  
  892. ogg_stream_state os_en, os_de;
  893. ogg_sync_state oy;
  894.  
  895. void checkpacket(ogg_packet *op,int len, int no, int pos){
  896.   long j;
  897.   static int sequence=0;
  898.   static int lastno=0;
  899.  
  900.   if(op->bytes!=len){
  901.     fprintf(stderr,"incorrect packet length!\n");
  902.     exit(1);
  903.   }
  904.   if(op->granulepos!=pos){
  905.     fprintf(stderr,"incorrect packet position!\n");
  906.     exit(1);
  907.   }
  908.  
  909.   /* packet number just follows sequence/gap; adjust the input number
  910.      for that */
  911.   if(no==0){
  912.     sequence=0;
  913.   }else{
  914.     sequence++;
  915.     if(no>lastno+1)
  916.       sequence++;
  917.   }
  918.   lastno=no;
  919.   if(op->packetno!=sequence){
  920.     fprintf(stderr,"incorrect packet sequence %ld != %d\n",
  921.         (long)(op->packetno),sequence);
  922.     exit(1);
  923.   }
  924.  
  925.   /* Test data */
  926.   for(j=0;j<op->bytes;j++)
  927.     if(op->packet[j]!=((j+no)&0xff)){
  928.       fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
  929.           j,op->packet[j],(j+no)&0xff);
  930.       exit(1);
  931.     }
  932. }
  933.  
  934. void check_page(unsigned char *data,const int *header,ogg_page *og){
  935.   long j;
  936.   /* Test data */
  937.   for(j=0;j<og->body_len;j++)
  938.     if(og->body[j]!=data[j]){
  939.       fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
  940.           j,data[j],og->body[j]);
  941.       exit(1);
  942.     }
  943.  
  944.   /* Test header */
  945.   for(j=0;j<og->header_len;j++){
  946.     if(og->header[j]!=header[j]){
  947.       fprintf(stderr,"header content mismatch at pos %ld:\n",j);
  948.       for(j=0;j<header[26]+27;j++)
  949.     fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
  950.       fprintf(stderr,"\n");
  951.       exit(1);
  952.     }
  953.   }
  954.   if(og->header_len!=header[26]+27){
  955.     fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
  956.         og->header_len,header[26]+27);
  957.     exit(1);
  958.   }
  959. }
  960.  
  961. void print_header(ogg_page *og){
  962.   int j;
  963.   fprintf(stderr,"\nHEADER:\n");
  964.   fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
  965.       og->header[0],og->header[1],og->header[2],og->header[3],
  966.       (int)og->header[4],(int)og->header[5]);
  967.  
  968.   fprintf(stderr,"  granulepos: %d  serialno: %d  pageno: %ld\n",
  969.       (og->header[9]<<24)|(og->header[8]<<16)|
  970.       (og->header[7]<<8)|og->header[6],
  971.       (og->header[17]<<24)|(og->header[16]<<16)|
  972.       (og->header[15]<<8)|og->header[14],
  973.       ((long)(og->header[21])<<24)|(og->header[20]<<16)|
  974.       (og->header[19]<<8)|og->header[18]);
  975.  
  976.   fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
  977.       (int)og->header[22],(int)og->header[23],
  978.       (int)og->header[24],(int)og->header[25],
  979.       (int)og->header[26]);
  980.  
  981.   for(j=27;j<og->header_len;j++)
  982.     fprintf(stderr,"%d ",(int)og->header[j]);
  983.   fprintf(stderr,")\n\n");
  984. }
  985.  
  986. void copy_page(ogg_page *og){
  987.   unsigned char *temp=_ogg_malloc(og->header_len);
  988.   memcpy(temp,og->header,og->header_len);
  989.   og->header=temp;
  990.  
  991.   temp=_ogg_malloc(og->body_len);
  992.   memcpy(temp,og->body,og->body_len);
  993.   og->body=temp;
  994. }
  995.  
  996. void error(void){
  997.   fprintf(stderr,"error!\n");
  998.   exit(1);
  999. }
  1000.  
  1001. /* 17 only */
  1002. const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
  1003.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1004.                0x01,0x02,0x03,0x04,0,0,0,0,
  1005.                0x15,0xed,0xec,0x91,
  1006.                1,
  1007.                17};
  1008.  
  1009. /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
  1010. const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
  1011.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1012.                0x01,0x02,0x03,0x04,0,0,0,0,
  1013.                0x59,0x10,0x6c,0x2c,
  1014.                1,
  1015.                17};
  1016. const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
  1017.                0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
  1018.                0x01,0x02,0x03,0x04,1,0,0,0,
  1019.                0x89,0x33,0x85,0xce,
  1020.                13,
  1021.                254,255,0,255,1,255,245,255,255,0,
  1022.                255,255,90};
  1023.  
  1024. /* nil packets; beginning,middle,end */
  1025. const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
  1026.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1027.                0x01,0x02,0x03,0x04,0,0,0,0,
  1028.                0xff,0x7b,0x23,0x17,
  1029.                1,
  1030.                0};
  1031. const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
  1032.                0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
  1033.                0x01,0x02,0x03,0x04,1,0,0,0,
  1034.                0x5c,0x3f,0x66,0xcb,
  1035.                17,
  1036.                17,254,255,0,0,255,1,0,255,245,255,255,0,
  1037.                255,255,90,0};
  1038.  
  1039. /* large initial packet */
  1040. const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
  1041.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1042.                0x01,0x02,0x03,0x04,0,0,0,0,
  1043.                0x01,0x27,0x31,0xaa,
  1044.                18,
  1045.                255,255,255,255,255,255,255,255,
  1046.                255,255,255,255,255,255,255,255,255,10};
  1047.  
  1048. const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
  1049.                0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
  1050.                0x01,0x02,0x03,0x04,1,0,0,0,
  1051.                0x7f,0x4e,0x8a,0xd2,
  1052.                4,
  1053.                255,4,255,0};
  1054.  
  1055.  
  1056. /* continuing packet test */
  1057. const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
  1058.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1059.                0x01,0x02,0x03,0x04,0,0,0,0,
  1060.                0xff,0x7b,0x23,0x17,
  1061.                1,
  1062.                0};
  1063.  
  1064. const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
  1065.                0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1066.                0x01,0x02,0x03,0x04,1,0,0,0,
  1067.                0x34,0x24,0xd5,0x29,
  1068.                17,
  1069.                255,255,255,255,255,255,255,255,
  1070.                255,255,255,255,255,255,255,255,255};
  1071.  
  1072. const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
  1073.                0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
  1074.                0x01,0x02,0x03,0x04,2,0,0,0,
  1075.                0xc8,0xc3,0xcb,0xed,
  1076.                5,
  1077.                10,255,4,255,0};
  1078.  
  1079.  
  1080. /* page with the 255 segment limit */
  1081. const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
  1082.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1083.                0x01,0x02,0x03,0x04,0,0,0,0,
  1084.                0xff,0x7b,0x23,0x17,
  1085.                1,
  1086.                0};
  1087.  
  1088. const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
  1089.                0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
  1090.                0x01,0x02,0x03,0x04,1,0,0,0,
  1091.                0xed,0x2a,0x2e,0xa7,
  1092.                255,
  1093.                10,10,10,10,10,10,10,10,
  1094.                10,10,10,10,10,10,10,10,
  1095.                10,10,10,10,10,10,10,10,
  1096.                10,10,10,10,10,10,10,10,
  1097.                10,10,10,10,10,10,10,10,
  1098.                10,10,10,10,10,10,10,10,
  1099.                10,10,10,10,10,10,10,10,
  1100.                10,10,10,10,10,10,10,10,
  1101.                10,10,10,10,10,10,10,10,
  1102.                10,10,10,10,10,10,10,10,
  1103.                10,10,10,10,10,10,10,10,
  1104.                10,10,10,10,10,10,10,10,
  1105.                10,10,10,10,10,10,10,10,
  1106.                10,10,10,10,10,10,10,10,
  1107.                10,10,10,10,10,10,10,10,
  1108.                10,10,10,10,10,10,10,10,
  1109.                10,10,10,10,10,10,10,10,
  1110.                10,10,10,10,10,10,10,10,
  1111.                10,10,10,10,10,10,10,10,
  1112.                10,10,10,10,10,10,10,10,
  1113.                10,10,10,10,10,10,10,10,
  1114.                10,10,10,10,10,10,10,10,
  1115.                10,10,10,10,10,10,10,10,
  1116.                10,10,10,10,10,10,10,10,
  1117.                10,10,10,10,10,10,10,10,
  1118.                10,10,10,10,10,10,10,10,
  1119.                10,10,10,10,10,10,10,10,
  1120.                10,10,10,10,10,10,10,10,
  1121.                10,10,10,10,10,10,10,10,
  1122.                10,10,10,10,10,10,10,10,
  1123.                10,10,10,10,10,10,10,10,
  1124.                10,10,10,10,10,10,10};
  1125.  
  1126. const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
  1127.                0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
  1128.                0x01,0x02,0x03,0x04,2,0,0,0,
  1129.                0x6c,0x3b,0x82,0x3d,
  1130.                1,
  1131.                50};
  1132.  
  1133.  
  1134. /* packet that overspans over an entire page */
  1135. const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
  1136.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1137.                0x01,0x02,0x03,0x04,0,0,0,0,
  1138.                0xff,0x7b,0x23,0x17,
  1139.                1,
  1140.                0};
  1141.  
  1142. const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
  1143.                0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
  1144.                0x01,0x02,0x03,0x04,1,0,0,0,
  1145.                0x3c,0xd9,0x4d,0x3f,
  1146.                17,
  1147.                100,255,255,255,255,255,255,255,255,
  1148.                255,255,255,255,255,255,255,255};
  1149.  
  1150. const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
  1151.                0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
  1152.                0x01,0x02,0x03,0x04,2,0,0,0,
  1153.                0xbd,0xd5,0xb5,0x8b,
  1154.                17,
  1155.                255,255,255,255,255,255,255,255,
  1156.                255,255,255,255,255,255,255,255,255};
  1157.  
  1158. const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
  1159.                0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
  1160.                0x01,0x02,0x03,0x04,3,0,0,0,
  1161.                0xef,0xdd,0x88,0xde,
  1162.                7,
  1163.                255,255,75,255,4,255,0};
  1164.  
  1165. /* packet that overspans over an entire page */
  1166. const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
  1167.                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1168.                0x01,0x02,0x03,0x04,0,0,0,0,
  1169.                0xff,0x7b,0x23,0x17,
  1170.                1,
  1171.                0};
  1172.  
  1173. const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
  1174.                0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
  1175.                0x01,0x02,0x03,0x04,1,0,0,0,
  1176.                0x3c,0xd9,0x4d,0x3f,
  1177.                17,
  1178.                100,255,255,255,255,255,255,255,255,
  1179.                255,255,255,255,255,255,255,255};
  1180.  
  1181. const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
  1182.                0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
  1183.                0x01,0x02,0x03,0x04,2,0,0,0,
  1184.                0xd4,0xe0,0x60,0xe5,
  1185.                1,0};
  1186.  
  1187. void test_pack(const int *pl, const int **headers){
  1188.   unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
  1189.   long inptr=0;
  1190.   long outptr=0;
  1191.   long deptr=0;
  1192.   long depacket=0;
  1193.   long granule_pos=7,pageno=0;
  1194.   int i,j,packets,pageout=0;
  1195.   int eosflag=0;
  1196.   int bosflag=0;
  1197.  
  1198.   ogg_stream_reset(&os_en);
  1199.   ogg_stream_reset(&os_de);
  1200.   ogg_sync_reset(&oy);
  1201.  
  1202.   for(packets=0;;packets++)if(pl[packets]==-1)break;
  1203.  
  1204.   for(i=0;i<packets;i++){
  1205.     /* construct a test packet */
  1206.     ogg_packet op;
  1207.     int len=pl[i];
  1208.     
  1209.     op.packet=data+inptr;
  1210.     op.bytes=len;
  1211.     op.e_o_s=(pl[i+1]<0?1:0);
  1212.     op.granulepos=granule_pos;
  1213.  
  1214.     granule_pos+=1024;
  1215.  
  1216.     for(j=0;j<len;j++)data[inptr++]=i+j;
  1217.  
  1218.     /* submit the test packet */
  1219.     ogg_stream_packetin(&os_en,&op);
  1220.  
  1221.     /* retrieve any finished pages */
  1222.     {
  1223.       ogg_page og;
  1224.       
  1225.       while(ogg_stream_pageout(&os_en,&og)){
  1226.     /* We have a page.  Check it carefully */
  1227.  
  1228.     fprintf(stderr,"%ld, ",pageno);
  1229.  
  1230.     if(headers[pageno]==NULL){
  1231.       fprintf(stderr,"coded too many pages!\n");
  1232.       exit(1);
  1233.     }
  1234.  
  1235.     check_page(data+outptr,headers[pageno],&og);
  1236.  
  1237.     outptr+=og.body_len;
  1238.     pageno++;
  1239.  
  1240.     /* have a complete page; submit it to sync/decode */
  1241.  
  1242.     {
  1243.       ogg_page og_de;
  1244.       ogg_packet op_de,op_de2;
  1245.       char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
  1246.       memcpy(buf,og.header,og.header_len);
  1247.       memcpy(buf+og.header_len,og.body,og.body_len);
  1248.       ogg_sync_wrote(&oy,og.header_len+og.body_len);
  1249.  
  1250.       while(ogg_sync_pageout(&oy,&og_de)>0){
  1251.         /* got a page.  Happy happy.  Verify that it's good. */
  1252.         
  1253.         check_page(data+deptr,headers[pageout],&og_de);
  1254.         deptr+=og_de.body_len;
  1255.         pageout++;
  1256.  
  1257.         /* submit it to deconstitution */
  1258.         ogg_stream_pagein(&os_de,&og_de);
  1259.  
  1260.         /* packets out? */
  1261.         while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
  1262.           ogg_stream_packetpeek(&os_de,NULL);
  1263.           ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
  1264.           
  1265.           /* verify peek and out match */
  1266.           if(memcmp(&op_de,&op_de2,sizeof(op_de))){
  1267.         fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
  1268.             depacket);
  1269.         exit(1);
  1270.           }
  1271.  
  1272.           /* verify the packet! */
  1273.           /* check data */
  1274.           if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
  1275.         fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
  1276.             depacket);
  1277.         exit(1);
  1278.           }
  1279.           /* check bos flag */
  1280.           if(bosflag==0 && op_de.b_o_s==0){
  1281.         fprintf(stderr,"b_o_s flag not set on packet!\n");
  1282.         exit(1);
  1283.           }
  1284.           if(bosflag && op_de.b_o_s){
  1285.         fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
  1286.         exit(1);
  1287.           }
  1288.           bosflag=1;
  1289.           depacket+=op_de.bytes;
  1290.           
  1291.           /* check eos flag */
  1292.           if(eosflag){
  1293.         fprintf(stderr,"Multiple decoded packets with eos flag!\n");
  1294.         exit(1);
  1295.           }
  1296.  
  1297.           if(op_de.e_o_s)eosflag=1;
  1298.  
  1299.           /* check granulepos flag */
  1300.           if(op_de.granulepos!=-1){
  1301.         fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
  1302.           }
  1303.         }
  1304.       }
  1305.     }
  1306.       }
  1307.     }
  1308.   }
  1309.   _ogg_free(data);
  1310.   if(headers[pageno]!=NULL){
  1311.     fprintf(stderr,"did not write last page!\n");
  1312.     exit(1);
  1313.   }
  1314.   if(headers[pageout]!=NULL){
  1315.     fprintf(stderr,"did not decode last page!\n");
  1316.     exit(1);
  1317.   }
  1318.   if(inptr!=outptr){
  1319.     fprintf(stderr,"encoded page data incomplete!\n");
  1320.     exit(1);
  1321.   }
  1322.   if(inptr!=deptr){
  1323.     fprintf(stderr,"decoded page data incomplete!\n");
  1324.     exit(1);
  1325.   }
  1326.   if(inptr!=depacket){
  1327.     fprintf(stderr,"decoded packet data incomplete!\n");
  1328.     exit(1);
  1329.   }
  1330.   if(!eosflag){
  1331.     fprintf(stderr,"Never got a packet with EOS set!\n");
  1332.     exit(1);
  1333.   }
  1334.   fprintf(stderr,"ok.\n");
  1335. }
  1336.  
  1337. int main(void){
  1338.  
  1339.   ogg_stream_init(&os_en,0x04030201);
  1340.   ogg_stream_init(&os_de,0x04030201);
  1341.   ogg_sync_init(&oy);
  1342.  
  1343.   /* Exercise each code path in the framing code.  Also verify that
  1344.      the checksums are working.  */
  1345.  
  1346.   {
  1347.     /* 17 only */
  1348.     const int packets[]={17, -1};
  1349.     const int *headret[]={head1_0,NULL};
  1350.     
  1351.     fprintf(stderr,"testing single page encoding... ");
  1352.     test_pack(packets,headret);
  1353.   }
  1354.  
  1355.   {
  1356.     /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
  1357.     const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
  1358.     const int *headret[]={head1_1,head2_1,NULL};
  1359.     
  1360.     fprintf(stderr,"testing basic page encoding... ");
  1361.     test_pack(packets,headret);
  1362.   }
  1363.  
  1364.   {
  1365.     /* nil packets; beginning,middle,end */
  1366.     const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
  1367.     const int *headret[]={head1_2,head2_2,NULL};
  1368.     
  1369.     fprintf(stderr,"testing basic nil packets... ");
  1370.     test_pack(packets,headret);
  1371.   }
  1372.  
  1373.   {
  1374.     /* large initial packet */
  1375.     const int packets[]={4345,259,255,-1};
  1376.     const int *headret[]={head1_3,head2_3,NULL};
  1377.     
  1378.     fprintf(stderr,"testing initial-packet lacing > 4k... ");
  1379.     test_pack(packets,headret);
  1380.   }
  1381.  
  1382.   {
  1383.     /* continuing packet test */
  1384.     const int packets[]={0,4345,259,255,-1};
  1385.     const int *headret[]={head1_4,head2_4,head3_4,NULL};
  1386.     
  1387.     fprintf(stderr,"testing single packet page span... ");
  1388.     test_pack(packets,headret);
  1389.   }
  1390.  
  1391.   /* page with the 255 segment limit */
  1392.   {
  1393.  
  1394.     const int packets[]={0,10,10,10,10,10,10,10,10,
  1395.            10,10,10,10,10,10,10,10,
  1396.            10,10,10,10,10,10,10,10,
  1397.            10,10,10,10,10,10,10,10,
  1398.            10,10,10,10,10,10,10,10,
  1399.            10,10,10,10,10,10,10,10,
  1400.            10,10,10,10,10,10,10,10,
  1401.            10,10,10,10,10,10,10,10,
  1402.            10,10,10,10,10,10,10,10,
  1403.            10,10,10,10,10,10,10,10,
  1404.            10,10,10,10,10,10,10,10,
  1405.            10,10,10,10,10,10,10,10,
  1406.            10,10,10,10,10,10,10,10,
  1407.            10,10,10,10,10,10,10,10,
  1408.            10,10,10,10,10,10,10,10,
  1409.            10,10,10,10,10,10,10,10,
  1410.            10,10,10,10,10,10,10,10,
  1411.            10,10,10,10,10,10,10,10,
  1412.            10,10,10,10,10,10,10,10,
  1413.            10,10,10,10,10,10,10,10,
  1414.            10,10,10,10,10,10,10,10,
  1415.            10,10,10,10,10,10,10,10,
  1416.            10,10,10,10,10,10,10,10,
  1417.            10,10,10,10,10,10,10,10,
  1418.            10,10,10,10,10,10,10,10,
  1419.            10,10,10,10,10,10,10,10,
  1420.            10,10,10,10,10,10,10,10,
  1421.            10,10,10,10,10,10,10,10,
  1422.            10,10,10,10,10,10,10,10,
  1423.            10,10,10,10,10,10,10,10,
  1424.            10,10,10,10,10,10,10,10,
  1425.            10,10,10,10,10,10,10,50,-1};
  1426.     const int *headret[]={head1_5,head2_5,head3_5,NULL};
  1427.     
  1428.     fprintf(stderr,"testing max packet segments... ");
  1429.     test_pack(packets,headret);
  1430.   }
  1431.  
  1432.   {
  1433.     /* packet that overspans over an entire page */
  1434.     const int packets[]={0,100,9000,259,255,-1};
  1435.     const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
  1436.     
  1437.     fprintf(stderr,"testing very large packets... ");
  1438.     test_pack(packets,headret);
  1439.   }
  1440.  
  1441.   {
  1442.     /* term only page.  why not? */
  1443.     const int packets[]={0,100,4080,-1};
  1444.     const int *headret[]={head1_7,head2_7,head3_7,NULL};
  1445.     
  1446.     fprintf(stderr,"testing zero data page (1 nil packet)... ");
  1447.     test_pack(packets,headret);
  1448.   }
  1449.  
  1450.  
  1451.  
  1452.   {
  1453.     /* build a bunch of pages for testing */
  1454.     unsigned char *data=_ogg_malloc(1024*1024);
  1455.     int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
  1456.     int inptr=0,i,j;
  1457.     ogg_page og[5];
  1458.     
  1459.     ogg_stream_reset(&os_en);
  1460.  
  1461.     for(i=0;pl[i]!=-1;i++){
  1462.       ogg_packet op;
  1463.       int len=pl[i];
  1464.       
  1465.       op.packet=data+inptr;
  1466.       op.bytes=len;
  1467.       op.e_o_s=(pl[i+1]<0?1:0);
  1468.       op.granulepos=(i+1)*1000;
  1469.  
  1470.       for(j=0;j<len;j++)data[inptr++]=i+j;
  1471.       ogg_stream_packetin(&os_en,&op);
  1472.     }
  1473.  
  1474.     _ogg_free(data);
  1475.  
  1476.     /* retrieve finished pages */
  1477.     for(i=0;i<5;i++){
  1478.       if(ogg_stream_pageout(&os_en,&og[i])==0){
  1479.     fprintf(stderr,"Too few pages output building sync tests!\n");
  1480.     exit(1);
  1481.       }
  1482.       copy_page(&og[i]);
  1483.     }
  1484.  
  1485.     /* Test lost pages on pagein/packetout: no rollback */
  1486.     {
  1487.       ogg_page temp;
  1488.       ogg_packet test;
  1489.  
  1490.       fprintf(stderr,"Testing loss of pages... ");
  1491.  
  1492.       ogg_sync_reset(&oy);
  1493.       ogg_stream_reset(&os_de);
  1494.       for(i=0;i<5;i++){
  1495.     memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
  1496.            og[i].header_len);
  1497.     ogg_sync_wrote(&oy,og[i].header_len);
  1498.     memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
  1499.     ogg_sync_wrote(&oy,og[i].body_len);
  1500.       }
  1501.  
  1502.       ogg_sync_pageout(&oy,&temp);
  1503.       ogg_stream_pagein(&os_de,&temp);
  1504.       ogg_sync_pageout(&oy,&temp);
  1505.       ogg_stream_pagein(&os_de,&temp);
  1506.       ogg_sync_pageout(&oy,&temp);
  1507.       /* skip */
  1508.       ogg_sync_pageout(&oy,&temp);
  1509.       ogg_stream_pagein(&os_de,&temp);
  1510.  
  1511.       /* do we get the expected results/packets? */
  1512.       
  1513.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1514.       checkpacket(&test,0,0,0);
  1515.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1516.       checkpacket(&test,100,1,-1);
  1517.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1518.       checkpacket(&test,4079,2,3000);
  1519.       if(ogg_stream_packetout(&os_de,&test)!=-1){
  1520.     fprintf(stderr,"Error: loss of page did not return error\n");
  1521.     exit(1);
  1522.       }
  1523.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1524.       checkpacket(&test,76,5,-1);
  1525.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1526.       checkpacket(&test,34,6,-1);
  1527.       fprintf(stderr,"ok.\n");
  1528.     }
  1529.  
  1530.     /* Test lost pages on pagein/packetout: rollback with continuation */
  1531.     {
  1532.       ogg_page temp;
  1533.       ogg_packet test;
  1534.  
  1535.       fprintf(stderr,"Testing loss of pages (rollback required)... ");
  1536.  
  1537.       ogg_sync_reset(&oy);
  1538.       ogg_stream_reset(&os_de);
  1539.       for(i=0;i<5;i++){
  1540.     memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
  1541.            og[i].header_len);
  1542.     ogg_sync_wrote(&oy,og[i].header_len);
  1543.     memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
  1544.     ogg_sync_wrote(&oy,og[i].body_len);
  1545.       }
  1546.  
  1547.       ogg_sync_pageout(&oy,&temp);
  1548.       ogg_stream_pagein(&os_de,&temp);
  1549.       ogg_sync_pageout(&oy,&temp);
  1550.       ogg_stream_pagein(&os_de,&temp);
  1551.       ogg_sync_pageout(&oy,&temp);
  1552.       ogg_stream_pagein(&os_de,&temp);
  1553.       ogg_sync_pageout(&oy,&temp);
  1554.       /* skip */
  1555.       ogg_sync_pageout(&oy,&temp);
  1556.       ogg_stream_pagein(&os_de,&temp);
  1557.  
  1558.       /* do we get the expected results/packets? */
  1559.       
  1560.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1561.       checkpacket(&test,0,0,0);
  1562.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1563.       checkpacket(&test,100,1,-1);
  1564.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1565.       checkpacket(&test,4079,2,3000);
  1566.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1567.       checkpacket(&test,2956,3,4000);
  1568.       if(ogg_stream_packetout(&os_de,&test)!=-1){
  1569.     fprintf(stderr,"Error: loss of page did not return error\n");
  1570.     exit(1);
  1571.       }
  1572.       if(ogg_stream_packetout(&os_de,&test)!=1)error();
  1573.       checkpacket(&test,300,13,14000);
  1574.       fprintf(stderr,"ok.\n");
  1575.     }
  1576.     
  1577.     /* the rest only test sync */
  1578.     {
  1579.       ogg_page og_de;
  1580.       /* Test fractional page inputs: incomplete capture */
  1581.       fprintf(stderr,"Testing sync on partial inputs... ");
  1582.       ogg_sync_reset(&oy);
  1583.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
  1584.          3);
  1585.       ogg_sync_wrote(&oy,3);
  1586.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1587.       
  1588.       /* Test fractional page inputs: incomplete fixed header */
  1589.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
  1590.          20);
  1591.       ogg_sync_wrote(&oy,20);
  1592.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1593.       
  1594.       /* Test fractional page inputs: incomplete header */
  1595.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
  1596.          5);
  1597.       ogg_sync_wrote(&oy,5);
  1598.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1599.       
  1600.       /* Test fractional page inputs: incomplete body */
  1601.       
  1602.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
  1603.          og[1].header_len-28);
  1604.       ogg_sync_wrote(&oy,og[1].header_len-28);
  1605.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1606.       
  1607.       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
  1608.       ogg_sync_wrote(&oy,1000);
  1609.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1610.       
  1611.       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
  1612.          og[1].body_len-1000);
  1613.       ogg_sync_wrote(&oy,og[1].body_len-1000);
  1614.       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
  1615.       
  1616.       fprintf(stderr,"ok.\n");
  1617.     }
  1618.  
  1619.     /* Test fractional page inputs: page + incomplete capture */
  1620.     {
  1621.       ogg_page og_de;
  1622.       fprintf(stderr,"Testing sync on 1+partial inputs... ");
  1623.       ogg_sync_reset(&oy); 
  1624.  
  1625.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
  1626.          og[1].header_len);
  1627.       ogg_sync_wrote(&oy,og[1].header_len);
  1628.  
  1629.       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
  1630.          og[1].body_len);
  1631.       ogg_sync_wrote(&oy,og[1].body_len);
  1632.  
  1633.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
  1634.          20);
  1635.       ogg_sync_wrote(&oy,20);
  1636.       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
  1637.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1638.  
  1639.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
  1640.          og[1].header_len-20);
  1641.       ogg_sync_wrote(&oy,og[1].header_len-20);
  1642.       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
  1643.          og[1].body_len);
  1644.       ogg_sync_wrote(&oy,og[1].body_len);
  1645.       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
  1646.  
  1647.       fprintf(stderr,"ok.\n");
  1648.     }
  1649.     
  1650.     /* Test recapture: garbage + page */
  1651.     {
  1652.       ogg_page og_de;
  1653.       fprintf(stderr,"Testing search for capture... ");
  1654.       ogg_sync_reset(&oy); 
  1655.       
  1656.       /* 'garbage' */
  1657.       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
  1658.          og[1].body_len);
  1659.       ogg_sync_wrote(&oy,og[1].body_len);
  1660.  
  1661.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
  1662.          og[1].header_len);
  1663.       ogg_sync_wrote(&oy,og[1].header_len);
  1664.  
  1665.       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
  1666.          og[1].body_len);
  1667.       ogg_sync_wrote(&oy,og[1].body_len);
  1668.  
  1669.       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
  1670.          20);
  1671.       ogg_sync_wrote(&oy,20);
  1672.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1673.       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
  1674.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1675.  
  1676.       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
  1677.          og[2].header_len-20);
  1678.       ogg_sync_wrote(&oy,og[2].header_len-20);
  1679.       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
  1680.          og[2].body_len);
  1681.       ogg_sync_wrote(&oy,og[2].body_len);
  1682.       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
  1683.  
  1684.       fprintf(stderr,"ok.\n");
  1685.     }
  1686.  
  1687.     /* Test recapture: page + garbage + page */
  1688.     {
  1689.       ogg_page og_de;
  1690.       fprintf(stderr,"Testing recapture... ");
  1691.       ogg_sync_reset(&oy); 
  1692.  
  1693.       memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
  1694.          og[1].header_len);
  1695.       ogg_sync_wrote(&oy,og[1].header_len);
  1696.  
  1697.       memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
  1698.          og[1].body_len);
  1699.       ogg_sync_wrote(&oy,og[1].body_len);
  1700.  
  1701.       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
  1702.          og[2].header_len);
  1703.       ogg_sync_wrote(&oy,og[2].header_len);
  1704.  
  1705.       memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
  1706.          og[2].header_len);
  1707.       ogg_sync_wrote(&oy,og[2].header_len);
  1708.  
  1709.       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
  1710.  
  1711.       memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
  1712.          og[2].body_len-5);
  1713.       ogg_sync_wrote(&oy,og[2].body_len-5);
  1714.  
  1715.       memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
  1716.          og[3].header_len);
  1717.       ogg_sync_wrote(&oy,og[3].header_len);
  1718.  
  1719.       memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
  1720.          og[3].body_len);
  1721.       ogg_sync_wrote(&oy,og[3].body_len);
  1722.  
  1723.       if(ogg_sync_pageout(&oy,&og_de)>0)error();
  1724.       if(ogg_sync_pageout(&oy,&og_de)<=0)error();
  1725.  
  1726.       fprintf(stderr,"ok.\n");
  1727.     }
  1728.   }    
  1729.  
  1730.   return(0);
  1731. }
  1732.  
  1733. #endif
  1734.  
  1735.  
  1736.  
  1737.  
  1738.